<?php

/**
 * ECTouch Open Source Project
 * ============================================================================
 * Copyright (c) 2012-2014 liuwave@qq.com All rights reserved.
 * ----------------------------------------------------------------------------
 * 文件名称：wxpay.php
 * ----------------------------------------------------------------------------
 * 功能描述：微信手机支付插件
 * ----------------------------------------------------------------------------
 *
 * ----------------------------------------------------------------------------
 */
/* 访问控制 */
if (!defined('IN_ECTOUCH')) {
    die('Deny Access');
}



$payment_lang = ROOT_PATH . 'plugins/payment/language/' . C('lang') . '/' . basename(__FILE__);

if (file_exists($payment_lang)) {
    include_once ($payment_lang);
    L($_LANG);
}

/* 模块的基本信息 */
if (isset($set_modules) && $set_modules == TRUE) {
    $i = isset($modules) ? count($modules) : 0;
    /* 代码 */
    $modules[$i]['code'] = basename(__FILE__, '.php');
    /* 描述对应的语言项 */
    $modules[$i]['desc'] = 'wxpay_desc';
    /* 是否支持货到付款 */
    $modules[$i]['is_cod'] = '0';
    /* 是否支持在线支付 */
    $modules[$i]['is_online'] = '1';
    /* 作者 */
    $modules[$i]['author'] = 'xmlwch@126.com';
    /* 网址 */
    $modules[$i]['website'] = '';
    /* 版本号 */
    $modules[$i]['version'] = '1.0';
    /* 配置信息 */

    /* 配置信息 */
    $modules[$i]['config'] = array(
        array('name' => 'wxpay_appid', 'type' => 'text', 'value' => ''),
        array('name' => 'wxpay_appsecret', 'type' => 'text', 'value' => ''),
        array('name' => 'wxpay_mchid', 'type' => 'text', 'value' => ''),
        array('name' => 'wxpay_key', 'type' => 'text', 'value' => ''),
    );

    return;
}

/**
 * 微信支付类
 */
class wxpay {

    var $parameters; // cft 参数
    var $payment; // 配置信息

    /**
     * 生成支付代码
     *
     * @param array $order
     *            订单信息
     * @param array $payment
     *            支付方式信息
     */

    function get_code($order, $payment) {
        if (!defined('EC_CHARSET')) {
            $charset = 'utf-8';
        } else {
            $charset = EC_CHARSET;
        }

        $charset = strtoupper($charset);
        // 配置参数
        $this->payment = $payment;

        if ((0 == $_REQUEST['u']) && empty($_SESSION['user_id'])) {
            return '<div style="text-align:center"><button class="btn btn-primary" type="button" disabled>请先登陆</button></div>';
        }




        $notify_url = __URL__ . "/respondwx.php";


        $this->logResult("log::get_code::notify_url:" . $notify_url);

        $this->setParameter("body", $order['order_sn']); // 商品描述
        $this->setParameter("out_trade_no", $order['order_sn'] . 'O' . $order['log_id'] . 'O' . $order['order_amount'] * 100); // 商户订单号
        $this->setParameter("total_fee", $order['order_amount'] * 100); // 总金额
        $this->setParameter("notify_url", $notify_url); // 通知地址
        $this->setParameter("trade_type", "MWEB"); // 交易类型
//        $this->setParameter("input_charset", $charset);
        $this->setParameter("scene_info", '{"h5_info":{"type": "Wap","wap_url": "https://shop.ha101.cn","wap_name": "掌上淮安"}}');
        $prepay_id = $this->getPrepayId();


        if (empty($prepay_id)) {
            return '<div style="text-align:center"><button class="btn btn-primary" type="button" disabled>' . L("wxpay_not_prepayid_button") . '</button></div>';
        }
        if ($prepay_id['return_code'] == "SUCCESS") {
            if ($prepay_id['err_code'] == "ORDERPAID") {
                //已经完成订单
                return '<div style="text-align:center"><button class="btn btn-primary" type="button" disabled>' . $prepay_id['err_code_des'] . '请联系客服人员</button></div>';
            }
            if ($prepay_id['result_code'] == "SUCCESS") {
                $jtourl = __URL__ . "/wxrespond.php?" . http_build_query($_REQUEST, "", "&");
                $jtourl = urlencode($jtourl);
                $button = '<div><input type="button" class="btn btn-info ect-btn-info ect-colorf ect-bg" onclick="javascript:location.href=\'' . $prepay_id['mweb_url'] . '&redirect_url=' . $jtourl . ' \'" value="' . L("wxpay_button") . '" class="c-btn3" /></div>';
            } else {
                return '<div style="text-align:center"><button class="btn btn-primary" type="button" disabled>' . $prepay_id['err_code_des'] . '</button></div>';
            }
        }
        return $button;
    }

    function logResult($word = '', $var = array()) {
        if (!WXPAY_DEBUG) {
            return true;
        }
        $output = strftime("%Y%m%d %H:%M:%S", time()) . "\n";
        $output .= $word . "\n";
        if (!empty($var)) {
            $output .= print_r($var, true) . "\n";
        }
        $output.="\n";

        $log_path = ROOT_PATH . "/data/log/";
        if (!is_dir($log_path)) {
            @mkdir($log_path, 0777, true);
        }

        file_put_contents($log_path . "wx.txt", $output, FILE_APPEND | LOCK_EX);
    }

    /**
     * 响应操作
     */
    function callback($data) {
        if (empty($data['u']) || empty($data['order_id'])) {
            return "缺少参数，请及时和我们取得联系。";
        }
        $sql = "SELECT * FROM ecs_order_info WHERE order_id='{$data['order_id']}' AND user_id='{$data['u']}'";
        $model = Model();
        $ret = $model->query($sql);
        if (empty($ret)) {
            return "订单信息有误，请及时和我们取得联系。";
        }
        if ($ret[0]['pay_status'] == 2) {
            return "本次支付成功，请返回继续操作。";
        } else {
            return "本次支付失败，请及时和我们取得联系。";
        }
    }

    /**
     * 响应操作
     */
    function notify($data) {

        $this->logResult("log::notify::start:");
        $xml = $GLOBALS['HTTP_RAW_POST_DATA'];
        file_put_contents("/www/log/notify.log", date("Y-m-d H:i:s") . "-----notifyxml-------- \r\n" . $xml . "\r\n", FILE_APPEND);
        if (!empty($xml)) {
            $payment = model('Payment')->get_payment($data['code']);

            $this->payment = $payment;
            $postdata = $this->xmlToArray($xml);
            /* 检查插件文件是否存在，如果存在则验证支付是否成功，否则则返回失败信息 */
            //todo 部署后删除
            $this->logResult("log::notify::postdata", $postdata);
            // 微信端签名
            $wxsign = $postdata['sign'];
            unset($postdata['sign']);
            //todo 部署后删除
            $this->logResult("log::notify::wxsign", $wxsign);
            $sign = $this->getSign($postdata);
            //todo 部署后删除
            $this->logResult("log::notify::sign:", $sign);

            if ($wxsign == $sign) {
                // 交易成功
                if ($postdata['result_code'] == 'SUCCESS') {
                    // 获取log_id
                    $out_trade_no = explode('O', $postdata['out_trade_no']);
                    $order_sn = $out_trade_no[1]; // 订单号log_id
                    // 改变订单状态
                    //todo 部署后删除
                    $this->logResult("log::notify::out_trade_no:", $postdata['out_trade_no']);
                    model('Payment')->order_paid($order_sn, 2);
                }
                $returndata['return_code'] = 'SUCCESS';
            } else {
                $returndata['return_code'] = 'FAIL';
                $returndata['return_msg'] = '签名失败';
            }
        } else {
            $returndata['return_code'] = 'FAIL';
            $returndata['return_msg'] = '无数据返回';
        }

        //todo 部署后删除
        $this->logResult("log::notify::returndata", $returndata['return_code']);
        $xml = $this->arrayToXml($returndata);
        //todo 部署后删除
        $this->logResult("log::notify::returnxml", $xml);

        echo $xml;
        exit();
    }

    /**
     * 	作用：将xml转为array
     */
    public function xmlToArray($xml) {
        //将XML转为array
        $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $array_data;
    }

    /**
     * 	作用：array转xml
     */
    function arrayToXml($arr) {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml.="<" . $key . ">" . $val . "</" . $key . ">";
            } else
                $xml.="<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
        }
        $xml.="</xml>";
        return $xml;
    }

    function trimString($value) {
        $ret = null;
        if (null != $value) {
            $ret = $value;
            if (strlen($ret) == 0) {
                $ret = null;
            }
        }
        return $ret;
    }

    /**
     * 作用：产生随机字符串，不长于32位
     */
    public function createNoncestr($length = 32) {
        $chars = "abcdefghijklmnopqrstuvwxyz0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i ++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * 作用：设置请求参数
     */
    function setParameter($parameter, $parameterValue) {
        $this->parameters[$this->trimString($parameter)] = $this->trimString($parameterValue);
    }

    /**
     * 作用：生成签名
     */
    public function getSign($Obj) {
        foreach ($Obj as $k => $v) {
            $Parameters[$k] = $v;
        }
        // 签名步骤一：按字典序排序参数
        ksort($Parameters);

        $buff = "";
        foreach ($Parameters as $k => $v) {
            $buff .= $k . "=" . $v . "&";
        }
        $String = "";
        if (strlen($buff) > 0) {
            $String = substr($buff, 0, strlen($buff) - 1);
        }
        // echo '【string1】'.$String.'</br>';
        // 签名步骤二：在string后加入KEY
        $String = $String . "&key=" . $this->payment['wxpay_key'];
        // echo "【string2】".$String."</br>";
        // 签名步骤三：MD5加密
        $String = md5($String);
        // echo "【string3】 ".$String."</br>";
        // 签名步骤四：所有字符转为大写
        $result_ = strtoupper($String);
        // echo "【result】 ".$result_."</br>";
        return $result_;
    }

    /**
     * 	作用：以post方式提交xml到对应的接口url
     */
    public function postXmlCurl($xml, $url, $second = 30) {
        //初始化curl
        $ch = curl_init();
        //设置超时
        curl_setopt($ch, CURLOPT_TIMEOUT, $second);
        //这里设置代理，如果有的话
        //curl_setopt($ch,CURLOPT_PROXY, '8.8.8.8');
        //curl_setopt($ch,CURLOPT_PROXYPORT, 8080);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
        //设置header
        curl_setopt($ch, CURLOPT_HEADER, FALSE);
        //要求结果为字符串且输出到屏幕上
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        //post提交方式
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
        //运行curl
        $data = curl_exec($ch);
        //返回结果

        if (!$data) {
            $error = curl_errno($ch);
            $this->logResult("error::postXmlCurl::curl出错，错误码:$error,http://curl.haxx.se/libcurl/c/libcurl-errors.html 错误原因查询");
        }
        curl_close($ch);
        return $data;
    }

    /**
     * 获取mweb_url
     */
    function getPrepayId() {
        // 设置接口链接
        $url = "https://api.mch.weixin.qq.com/pay/unifiedorder";

        if ($this->parameters["out_trade_no"] == null) {

            $this->logResult("error::getPrepayId::缺少统一支付接口必填参数out_trade_no");
        } elseif ($this->parameters["body"] == null) {
            $this->logResult("error::getPrepayId::缺少统一支付接口必填参数body");
        } elseif ($this->parameters["total_fee"] == null) {
            $this->logResult("error::getPrepayId::缺少统一支付接口必填参数total_fee");
        } elseif ($this->parameters["notify_url"] == null) {
            $this->logResult("error::getPrepayId::缺少统一支付接口必填参数notify_url");
        } elseif ($this->parameters["trade_type"] == null) {
            $this->logResult("error::getPrepayId::缺少统一支付接口必填参数trade_type");
        } elseif ($this->parameters["trade_type"] == "JSAPI" && $this->parameters["openid"] == NULL) {
            $this->logResult("error::getPrepayId::统一支付接口中，缺少必填参数openid！trade_type为JSAPI时，openid为必填参数！");
        }
        $this->parameters["appid"] = $this->payment['wxpay_appid']; // 公众账号ID
        $this->parameters["mch_id"] = $this->payment['wxpay_mchid']; // 商户号
        $this->parameters["nonce_str"] = $this->createNoncestr(); // 随机字符串
//        $this->parameters["spbill_create_ip"] = $_SERVER['REMOTE_ADDR']; // 终端ip
        $this->parameters["spbill_create_ip"] = $this->getClientIP(); // 用户终端ip
        $this->parameters["sign"] = $this->getSign($this->parameters); // 签名
        $xml = $this->arrayToXml($this->parameters);
        file_put_contents("/www/log/pay.log", "\r\n" . $xml . "\r\n", FILE_APPEND);

        $response = $this->postXmlCurl($xml, $url, 30);
        file_put_contents("/www/log/pay.log", "\r\n" . $response . "\r\n", FILE_APPEND);
        //todo 部署后删除
        $this->logResult("log::getPrepayId::response", $response);
        //$response = Http::curlPost($url, $xml, 30);
        $result = $this->xmlToArray($response);
        return $result;
    }

    public function getClientIP() {
        $cip = "unknow";
        if ($_SERVER['REMOTE_ADDR']) {
            $cip = $_SERVER['REMOTE_ADDR'];
        } elseif (getenv("REMOTE_ADDR")) {
            $cip = getenv("REMOTE_ADDR");
        }
        return $cip;
    }

    /**
     * 作用：设置jsapi的参数
     */
    public function getParameters($prepay_id) {
        $jsApiObj["appId"] = $this->payment['wxpay_appid'];
        $timeStamp = time();
        $jsApiObj["timeStamp"] = "$timeStamp";
        $jsApiObj["nonceStr"] = $this->createNoncestr();
        $jsApiObj["package"] = "prepay_id=$prepay_id";
        $jsApiObj["signType"] = "MD5";
        $jsApiObj["paySign"] = $this->getSign($jsApiObj);
        $this->parameters = json_encode($jsApiObj);

        return $this->parameters;
    }

}
